# The following python-related tools and processes are supported:
#   * black
#   * coverage         (requires ".coveragerc")
#   * flake8
#   * pypi upload      (requires "~/.pypirc")
#   * tox / unittests  (requires "tox.ini")
#

PYTHON_BIN ?= python3

DIR_PYTHON_BUILD ?= $(DIR_BUILD)/python-lib
PYTHON_BDIST_ARGS = --dist-dir $(DIR_BUILD)/python-packages
PYTHON_BUILD_ARGS = --build-base "$(DIR_PYTHON_BUILD)"
PYTHON_INSTALL_ARGS = --root "$(abspath $(DESTDIR))"
DISABLE_PYTHON_TESTS ?= 0
DISABLE_PYTHON_LINT_FLAKE8 ?= 0
ENABLE_PYTHON_LINT_BLACK ?= 0
PYPI_UPLOAD_TARGET = https://pypi.python.org/pypi
DIR_PYTHON_COVERAGE_HTML = $(DIR_BUILD)/coverage-html
# detect if flake8 is available as an executable (e.g. Arch) or as a python module (e.g. Debian)
FLAKE8_BIN ?= $(shell hash flake8 2>/dev/null && echo "flake8" || echo "$(PYTHON_BIN) -m flake8")
FLAKE8_FILES ?= $(DIR_PYTHON_SETUP)
RUN_PYTHON = $(PYTHON_BIN)
BLACK_BIN ?= black
# projects may want to override this with something like "--target-version=py39"
BLACK_ARGS ?=
BLACK_FILES ?= $(DIR_PYTHON_SETUP)
PYTHON_TOX_FILE ?= $(DIR_PYTHON_SETUP)/tox.ini
PYTHON_TEST_POETRY_COMMAND ?= pytest
PYTHON_BUILD_SYSTEM ?= $(shell \
  if grep -q "^build-backend.*hatch" "$(PYTHON_PYPROJECT_FILE)"; then echo "hatchling"; \
  elif grep -q "^build-backend.*poetry" "$(PYTHON_PYPROJECT_FILE)"; then echo "poetry"; \
  elif [ -e "$(PYTHON_SETUP_FILE)" ]; then echo "setuptools"; \
  fi)
PYTHON_TEST_RUNNER ?= $(shell \
  if [ -e "$(PYTHON_TOX_FILE)" ]; then echo "tox"; \
  elif [ -e manage.py ]; then echo "django"; \
  elif [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  elif [ "$(PYTHON_BUILD_SYSTEM)" = "poetry" ]; then echo "poetry"; \
  else echo "generic"; \
  fi)
PYTHON_LINT_RUNNER ?= $(shell \
  if [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  else echo "generic"; \
  fi)
PYTHON_STYLE_RUNNER ?= $(shell \
  if [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  else echo "generic"; \
  fi)


.PHONY: help
help: help-python

.PHONY: help-python
help-python:
	@echo "Python-specific packaging targets:"
	@echo "    clean-python"
	@echo "    dist-python"
	@echo "    lint-python"
	@echo "    report-python"
	@echo "    style-python"
	@echo "    test-python"
	@echo "    upload-python"
	@echo

.PHONY: dist
dist: dist-python

.PHONY: install
install: install-python

.PHONY: lint
lint: lint-python

.PHONY: style
style: style-python

ifneq ($(DISABLE_PYTHON_TESTS),1)
.PHONY: test
test: test-python
endif

.PHONY: install-python
install-python:
	cd "$(DIR_PYTHON_SETUP)" && $(RUN_PYTHON) setup.py install $(PYTHON_INSTALL_ARGS)

.PHONY: dist-python
dist-python: clean-python
	cd "$(DIR_PYTHON_SETUP)" \
		&& $(RUN_PYTHON) setup.py build $(PYTHON_BUILD_ARGS) bdist $(PYTHON_BDIST_ARGS)

.PHONY: check-pypi-config
check-pypi-config:
	@# verify that the section for our internal target is not missing
	@if grep -q "^\[$(PYPI_UPLOAD_TARGET)\]$$" ~/.pypirc; then true; else \
		echo "ERROR: missing '$(PYPI_UPLOAD_TARGET)' section in ~/.pypirc: "\
		"take a look at pypirc.sample" >&2; \
		exit 1; \
	fi

.PHONY: upload
upload: upload-python

.PHONY: upload-python
upload-python: check-pypi-config
	cd "$(DIR_PYTHON_SETUP)" && $(RUN_PYTHON) setup.py sdist upload -r "$(PYPI_UPLOAD_TARGET)"


.PHONY: lint-python
ifeq ($(PYTHON_LINT_RUNNER),hatch)
lint-python: lint-python-hatch
else ifeq ($(PYTHON_LINT_RUNNER),generic)
ifeq ($(ENABLE_PYTHON_LINT_BLACK),1)
lint-python: lint-python-black
endif
ifneq ($(DISABLE_PYTHON_LINT_FLAKE8),1)
lint-python: lint-python-flake8
endif
endif

.PHONY: lint-python-black
lint-python-black:
	$(BLACK_BIN) --check $(BLACK_ARGS) $(BLACK_FILES)

.PHONY: lint-python-flake8
lint-python-flake8:
	$(FLAKE8_BIN) $(FLAKE8_FILES)

.PHONY: lint-python-hatch
lint-python-hatch:
	hatch run lint:all


.PHONY: style-python
ifeq ($(PYTHON_STYLE_RUNNER),hatch)
style-python: style-python-hatch
else ifeq ($(PYTHON_STYLE_RUNNER),generic)
style-python: style-python-black
endif

.PHONY: style-python-black
style-python-black:
	$(BLACK_BIN) $(BLACK_ARGS) $(BLACK_FILES)

.PHONY: style-python-hatch
style-python-hatch:
	hatch run lint:fmt


.PHONY: test-python
ifeq ($(PYTHON_TEST_RUNNER),tox)
test-python: test-python-tox
else ifeq ($(PYTHON_TEST_RUNNER),django)
test-python: test-python-django
else ifeq ($(PYTHON_TEST_RUNNER),hatch)
test-python: test-python-hatch
else ifeq ($(PYTHON_TEST_RUNNER),poetry)
test-python: test-python-poetry
else ifeq ($(PYTHON_TEST_RUNNER),generic)
test-python: test-python-generic
endif

.PHONY: test-python-tox
test-python-tox:
	tox

.PHONY: test-python-django
test-python-django:
	$(RUN_PYTHON) manage.py test

.PHONY: test-python-hatch
test-python-hatch:
	hatch run test

.PHONY: test-python-poetry
test-python-poetry:
	poetry run $(PYTHON_TEST_POETRY_COMMAND)

.PHONY: test-python-generic
test-python-generic:
	$(RUN_PYTHON) $(PYTHON_TEST_ARGS)


.PHONY: report
report: report-python

.PHONY: report-python
report-python:
	if [ -e .coveragerc ]; then $(MAKE) report-python-coverage; fi

.PHONY: report-python-coverage
report-python-coverage:
	@# run tests for coverage analysis
	$(RUN_PYTHON) -m coverage run $(PYTHON_TEST_ARGS)
	@# provide textual report
	$(RUN_PYTHON) -m coverage report
	$(RUN_PYTHON) -m coverage html --directory "$(DIR_PYTHON_COVERAGE_HTML)"
	@printf "Browse the coverage report:\n\tfile://%s/index.html\n" \
		"$(abspath $(DIR_PYTHON_COVERAGE_HTML))"
	@# run a visual browser if the DISPLAY variable is set
	@if [ -n "$$DISPLAY" ] && [ -n "$(COVERAGE_BROWSER_BIN)" ]; then \
		"$(COVERAGE_BROWSER_BIN)" "$(DIR_PYTHON_COVERAGE_HTML)/index.html"; fi

.PHONY: clean-python
clean-python:
	cd "$(DIR_PYTHON_SETUP)" && python3 setup.py clean || true
	@# datafile for python3-coverage
	$(RM) .coverage
	@# workaround for https://github.com/pypa/setuptools/issues/436
	$(RM) "$(DIR_PYTHON_SETUP)"/*.egg-info/SOURCES.txt

clean: clean-python
